﻿using System.Reflection;
using System.Text.Encodings.Web;
using System.Text.Json;
using System.Text.Unicode;
using ApiLib.Common;
using ApiLib.Common.Attributes.IocAttributes;
using ApiLib.Common.Filters;
using ApiLib.Common.MyJobs;
using ApiLib.Extras.Jwt;
using ApiLib.Models;
using ApiLib.Utils;
using ApiLib.Utils.Converters;
using Furion;
using Furion.Schedule;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.FileProviders;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using SqlSugar;

namespace ApiLib.AppStart;

/// <summary>
/// 
/// </summary>
public class AppCoreStartup : AppStartup
{
    /// <summary>
    /// 服务配置
    /// </summary>
    /// <param name="services"></param>
    public void ConfigureServices(IServiceCollection services)
    {
        GlobalConfig.AppCoreConfig?.InitAppConfig(); //初始胡配置

        foreach (var action in GlobalConfig.ConfigureServices)
        {
            action.Invoke(services);
        }

        if (WebUtil.UseJwt)
        {
            services.AddJwt<JwtHandler>(enableGlobalAuthorize: true); //可以使用jwt生成token
        }

        services.AddMyFilters(); //拦截

        services.AddHttpRemote(); //远程请求
        // services.AddRemoteRequest(); //远程请求
        services.AddCorsAccessor(); //跨域
        services.AddControllers()
            // .AddInjectWithUnifyResult() //统一返回，规范结果
            .AddInjectWithUnifyResult<DefaultResultProvider>() //统一返回，规范结果
            .AddJsonOptions(options =>
            {
                // PropertyNamingPolicy=JsonNamingPolicy.CamelCase驼峰命名，snake_case（带下划线），kebab-case（带连字符）
                // options.JsonSerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;
                //允许全部编码：解决中文编码问题
                options.JsonSerializerOptions.Encoder = JavaScriptEncoder.Create(UnicodeRanges.All);
                //允许尾部的逗号
                options.JsonSerializerOptions.AllowTrailingCommas = true;
                //忽略大小写
                options.JsonSerializerOptions.PropertyNameCaseInsensitive = true;
                //解决object序列化成JsonElement的问题
                options.JsonSerializerOptions.Converters.Add(new ObjectAsPrimitiveConverter());
                options.JsonSerializerOptions.Converters.Add(new SystemTextJsonConverter.BoolConverter());
                //时间序列化
                options.JsonSerializerOptions.Converters.AddDateTimeTypeConverters("yyyy-MM-dd HH:mm:ss");
            });

        services.AddTaskQueue();
        services.AddComponent(); //添加组件


        #region 日志

        services.AddFileLogging("logs/error/{0:yyyy}-{0:MM}-{0:dd}.log", options =>
        {
            options.FileNameRule = fileName => string.Format(fileName, DateTime.UtcNow);
            options.WriteFilter = message => message.LogLevel == LogLevel.Error;
        });
        services.AddFileLogging("logs/info/{0:yyyy}-{0:MM}-{0:dd}.log", options =>
        {
            options.FileNameRule = fileName => string.Format(fileName, DateTime.UtcNow);
            options.WriteFilter = message => message.LogLevel == LogLevel.Information;
        });

        #endregion

        #region 定时任务

        services.AddSchedule(builder =>
        {
            // builder.AddJob<MyOaJob>(TriggerBuilder.Cron("*/3 * * * *"));
            // builder.AddJob<MyOaJob>(Triggers.PeriodMinutes(3).SetRunOnStart(true)); //启动时执行，每3分钟执行
            if (GlobalConfig.UseDefaultSchedule)
            {
                //监视
                builder.AddMonitor<DefaultJobMonitor>();
                //执行器：处理超时、重试
                builder.AddExecutor<DefaultJobExecutor>();
                // builder.AddJob<MyDefaultTask>(Triggers.PeriodMinutes(3).SetRunOnStart(true));
            }

            // 自动打印任务日志
            builder.JobDetail.LogEnabled = true;
            //自动扫描继承IJob接口的任务，有PeriodAttribute特性的会执行
            builder.AddJob(App.EffectiveTypes.ScanToBuilders());
            //自定义
            foreach (var action in GlobalConfig.ScheduleOptionsBuilders)
            {
                action.Invoke(builder);
            }
        });

        #endregion

        #region SqlSugar

        services.AddDatabases();

        #endregion
        
    }

    /// <summary>
    /// APP配置
    /// </summary>
    /// <param name="app"></param>
    /// <param name="env"></param>
    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        foreach (var action in GlobalConfig.Configures)
        {
            action.Invoke(app, env);
        }

        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }

        // 添加规范化结果状态码(401,403)，需要在这里注册
        if (GlobalConfig.UseUnifyResultStatusCodes)
        {
            app.UseUnifyResultStatusCodes();
        }

        if (GlobalConfig.AppConfig != null && GlobalConfig.AppConfig.DefaultHttpLog)
        {
            //请求日志，在UseStaticFiles之前调用
            app.UseHttpLogging();
        }

        #region 静态文件

        // 默认静态资源调用，wwwroot
        if (GlobalConfig.UseStaticFiles)
        {
            app.UseStaticFiles();
            if (GlobalConfig.UseDefaultFiles)
            {
                app.UseDefaultFiles();
            }
        }

        // 配置模块化静态资源
        if (!string.IsNullOrEmpty(GlobalConfig.UploadPath))
        {
            var uploadPath = Path.Combine(AppContext.BaseDirectory, GlobalConfig.UploadPath);
            if (!Directory.Exists(uploadPath))
            {
                Directory.CreateDirectory(uploadPath);
            }

            app.UseFileServer(new FileServerOptions
            {
                FileProvider = new PhysicalFileProvider(uploadPath),
                RequestPath = "/" + GlobalConfig.UploadPath, // 后续所有资源都是通过 /模块名称/xxx.css 调用
                EnableDirectoryBrowsing = true,
                StaticFileOptions =
                {
                    ServeUnknownFileTypes = true,
                    OnPrepareResponse = context =>
                    {
                        context.Context.Response.Headers.AccessControlAllowOrigin = "*";
                        context.Context.Response.Headers.AccessControlAllowHeaders = "*";
                        context.Context.Response.Headers.AccessControlAllowMethods =
                            "PUT,POST,GET,DELETE,OPTIONS,HEAD,PATCH";
                    }
                },
            });
        }

        #endregion

        if (GlobalConfig.UseHttpsRedirection)
        {
            app.UseHttpsRedirection(); //http请求自动跳转到https
        }

        if (GlobalConfig.UseScheduleUI)
        {
            //定时任务UI
            app.UseScheduleUI(options =>
            {
                options.RequestPath = "/schedule"; // 默认schedule，必须以 / 开头且不以 / 结尾
                options.DisableOnProduction = true; //生产关闭
            });
        }

        app.UseRouting();
        app.UseCorsAccessor(); //跨域
        app.UseMiddleware<DefaultMiddleware>(); //中间件

        if (WebUtil.UseJwt)
        {
            // 使用拦截器时，不需要鉴权相关配置
            app.UseAuthentication(); //认证,添加Header，Authorization：Bearer token
            app.UseAuthorization(); //鉴权
        }

        app.UseInject("swagger"); //参数是swagger地址，应与launchSettings.json的launchUrl相同，为string.Empty时根路径是swagger地址
        app.UseEndpoints(endpoints => { endpoints.MapControllers(); });
    }
}

/// <summary>
/// 启动配置扩展方法
/// </summary>
public static class StartupExtend
{
    /// <summary>
    /// 添加拦截
    /// </summary>
    /// <param name="services"></param>
    public static void AddMyFilters(this IServiceCollection services)
    {
        // services.AddMvcFilter<MyAuthorizeFilter>(); //授权拦截，登陆拦截

        var childTypes = AssemblyUtil.GetChildTypes(typeof(IAsyncAuthorizationFilter), typeof(IAsyncActionFilter),
            typeof(IAsyncResourceFilter), typeof(IAsyncResultFilter));
        if (childTypes.Count > 0)
        {
            // Mvc 方式注册一，全局执行
            services.AddControllersWithViews(options =>
            {
                foreach (var childType in childTypes)
                {
                    options.Filters.Add(childType);
                }
            });
        }
    }

    /// <summary>
    /// 添加数据库
    /// </summary>
    /// <param name="services"></param>
    public static void AddDatabases(this IServiceCollection services)
    {
        //Redis
        /*{
            var redisConfig = GlobalConfig.AppConfig?.Redis ?? GlobalConfig.AppCoreConfig?.RedisConnectionString ?? "";
            if (!string.IsNullOrEmpty(redisConfig))
            {
                RedisCache.Init(redisConfig);
            }
        }*/

        {
            //读取配置文件的数据量
            var connStrings = App.GetConfig<Dictionary<string, string>>("ConnectionStrings");
            if (connStrings != null)
            {
                var dbTypes = Enum.GetValues<DbType>().ToList();
                foreach (var (key, value) in connStrings)
                {
                    var dbType = dbTypes.Get(type => key.ToUpper().StartsWith(type.ToString().ToUpper()));
                    if (dbType != null)
                    {
                        GlobalConfig.BaseConnectionConfigs.Add(new BaseConnectionConfig
                        {
                            ConfigId = key,
                            DbType = dbType.Value,
                            ConnectionString = value,
                        });
                    }
                }
            }
        }

        //获取App.GetService<ISqlSugarClient>()，或者构造注入ISqlSugarClient
        //如果多个数数据库传 List<ConnectionConfig>
        foreach (var config in GlobalConfig.BaseConnectionConfigs)
        {
            GlobalConfig.ConnectionConfigs.Add(new ConnectionConfig
            {
                ConfigId = config.ConfigId,
                DbType = config.DbType,
                ConnectionString = config.ConnectionString,
                IsAutoCloseConnection = true,
                AopEvents = config.AopEvents,
                ConfigureExternalServices = new ConfigureExternalServices()
                {
                    EntityService = (info, columnInfo) => //处理列名
                    {
                        if ((info.DeclaringType?.Namespace ?? "").StartsWith("ApiLib")) return;
                        // columnInfo.DbColumnName = columnInfo.DbColumnName.ToUnderLine();
                        columnInfo.DbColumnName=UtilMethods.ToUnderLine(columnInfo.DbColumnName);//驼峰转下划线方法
                        /*//支持string?和string  
                        if(columnInfo.IsPrimarykey==false&&new NullabilityInfoContext().Create(info).WriteState is NullabilityState.Nullable)
                        {
                            columnInfo.IsNullable = true;
                        }*/
                        if(columnInfo.IsPrimarykey==false)
                        {
                            columnInfo.IsNullable = true;
                        }
                    },
                    EntityNameService = (info, columnInfo) => //处理表名
                    {
                        // columnInfo.DbTableName = columnInfo.DbTableName.ToUnderLine(); //驼峰转下划线方法
                        if ((info.Namespace ?? "").StartsWith("ApiLib")) return;
                        var tableName = !string.IsNullOrEmpty(columnInfo.DbTableName)
                            ? columnInfo.DbTableName
                            : info.Name;
                        columnInfo.DbTableName=UtilMethods.ToUnderLine(tableName);//驼峰转下划线方法
                    }
                }
            });
        }

        var sqlSugar = new SqlSugarScope(GlobalConfig.ConnectionConfigs);
        services.AddSingleton<ISqlSugarClient>(sqlSugar); //这边是SqlSugarScope用AddSingleton
    }


    /// <summary>
    /// 注入组件
    /// </summary>
    /// <param name="services"></param>
    public static void AddComponent(this IServiceCollection services)
    {
        WebUtil.Components.ForEach(type =>
        {
            if (type.IsEnum || type.IsInterface || type.IsAbstract || type.IsSealed)
            {
                return;
            }

            if (type.GetCustomAttribute(typeof(ComponentAttribute)) is not ComponentAttribute component)
            {
                return;
            }

            var interfaces = type.GetInterfaces();
            switch (component.Type)
            {
                case DependencyType.Scoped:
                    services.AddScoped(type);
                    if (interfaces.Length > 0)
                    {
                        services.AddScoped(interfaces[0], type);
                    }

                    break;
                case DependencyType.Singleton:
                    services.AddSingleton(type);
                    if (interfaces.Length > 0)
                    {
                        services.AddSingleton(interfaces[0], type);
                    }

                    break;
                case DependencyType.Transient:
                    services.AddTransient(type);
                    if (interfaces.Length > 0)
                    {
                        services.AddTransient(interfaces[0], type);
                    }

                    break;
            }
        });
    }
}